package cn.yangjunda.multipart.commons;

import cn.yangjunda.multipart.MultipartFile;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * Created by juanda on 12/15/17.
 */
public class CommonsMultipartFile implements MultipartFile {

    protected static final Log logger = LogFactory.getLog(CommonsMultipartFile.class);

    private final FileItem fileItem;
    private final long size;

    public CommonsMultipartFile(FileItem fileItem){
        this.fileItem = fileItem;
        this.size = fileItem.getSize();
    }

    public FileItem getFileItem() {
        return fileItem;
    }

    public String getName() {
        return this.fileItem.getFieldName();
    }

    @Override
    public String getContentType() {
        return this.fileItem.getContentType();
    }

    @Override
    public boolean isEmpty() {
        return this.size == 0L;
    }

    @Override
    public long getSize() {
        return this.size;
    }

    @Override
    public byte[] getBytes() {
        if(!this.isAvailable()) {
            throw new IllegalStateException("File has been moved - cannot be read again");
        } else {
            byte[] bytes = this.fileItem.get();
            return bytes != null?bytes:new byte[0];
        }
    }

    @Override
    public InputStream getInputStream() throws IOException {
        if(!this.isAvailable()) {
            throw new IllegalStateException("File has been moved - cannot be read again");
        } else {
            InputStream inputStream = this.fileItem.getInputStream();
            return inputStream != null?inputStream:new ByteArrayInputStream(new byte[0]);
        }
    }

    @Override
    public String getOriginalFilename() {
        String filename = this.fileItem.getName();
        if(filename == null) {
            return "";
        } else {
            int pos = filename.lastIndexOf("/");
            if(pos == -1) {
                pos = filename.lastIndexOf("\\");
            }

            return pos != -1?filename.substring(pos + 1):filename;
        }
    }


    @Override
    public void transferTo(File dest) throws IOException, IllegalStateException {
        if(!this.isAvailable()) {
            throw new IllegalStateException("File has already been moved - cannot be transferred again");
        } else if(dest.exists() && !dest.delete()) {
            throw new IOException("Destination file [" + dest.getAbsolutePath() + "] already exists and could not be deleted");
        } else {
            try {
                this.fileItem.write(dest);
                if(logger.isDebugEnabled()) {
                    String ex = "transferred";
                    if(!this.fileItem.isInMemory()) {
                        ex = this.isAvailable()?"copied":"moved";
                    }

                    logger.debug("Multipart file \'" + this.getName() + "\' with original filename [" + this.getOriginalFilename() + "], stored " + this.getStorageDescription() + ": " + ex + " to [" + dest.getAbsolutePath() + "]");
                }

            } catch (FileUploadException var3) {
                throw new IllegalStateException(var3.getMessage());
            } catch (IOException var4) {
                throw var4;
            } catch (Exception var5) {
                logger.error("Could not transfer to file", var5);
                throw new IOException("Could not transfer to file: " + var5.getMessage());
            }
        }
    }

    protected boolean isAvailable() {
        return this.fileItem.isInMemory() || (this.fileItem instanceof DiskFileItem ? ((DiskFileItem) this.fileItem).getStoreLocation().exists() : this.fileItem.getSize() == this.size);
    }

    public String getStorageDescription() {
        return this.fileItem.isInMemory()?"in memory":(this.fileItem instanceof DiskFileItem?"at [" + ((DiskFileItem)this.fileItem).getStoreLocation().getAbsolutePath() + "]":"on disk");
    }
}
